package com.bill99.rpc.reference.hessian;

import java.lang.reflect.InvocationTargetException;

import org.aopalliance.intercept.MethodInvocation;

import com.bill99.rpc.RpcException;
import com.bill99.rpc.cluster.LoadBalance;
import com.bill99.rpc.cluster.ServiceNode;
import com.bill99.rpc.common.util.UrlUtils;
import com.bill99.rpc.reference.ReferenceSupport;

/**
 * @author sheng.zhang
 */
public class HessianReferenceBean extends ReferenceSupport {

	private static final long serialVersionUID = 1L;

	@Override
	protected Object doInvoke(MethodInvocation invocation,
			LoadBalance loadBalance, boolean failover) throws RpcException {
		int len = serviceNodes.size();
		for (int i = 0; i < len; i++) {
			ServiceNode serviceNode = loadBalance.getInvokeServiceNode(
					getAvailableServiceNodes(), referenceUrl);
			String hessianUrl = UrlUtils.buildHessianUrl(serviceNode
					.getServiceUrl());
			Object hessianProxy = HessianProxyPool.getPool().getProxy(
					serviceNode.getServiceUrl());
			try {
				logger.info(
						"Invoke Hessian proxy for remote service: {}, method: {}, arguments: {}",
						new Object[] { hessianUrl,
								invocation.getMethod().getName(),
								invocation.getArguments() });
				Object result = invocation.getMethod().invoke(hessianProxy,
						invocation.getArguments());
				logger.info("Service result: {}", result);
				return result;
			} catch (InvocationTargetException t) {
				logger.warn(
						"Failed to invoke Hessian proxy for remote service:[{}], cause: {}",
						new Object[] { hessianUrl,
								t.getTargetException().getCause() });
				notifyUnavailableServiceNode(serviceNode);
				if (failover) {
					continue;
				} else {
					throw new RpcException(RpcException.UNKNOWN_EXCEPTION, t
							.getTargetException().getCause().getMessage(), t
							.getTargetException().getCause());
				}
			} catch (Throwable t) {
				logger.warn(
						"Failed to invoke Hessian proxy for remote service:[{}], cause: {}",
						new Object[] { hessianUrl, t.getCause() });
				notifyUnavailableServiceNode(serviceNode);
				if (failover) {
					continue;
				} else {
					throw new RpcException(RpcException.UNKNOWN_EXCEPTION,
							t.getMessage(), t);
				}

			}
		}
		throw new RpcException(RpcException.FAILOVER_EXCEPTION,
				"Failed to invoke Hessian proxy for all remote service");
	}

}
